﻿using Jungo.wdapi_dotnet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/*App.config文件
 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<startup useLegacyV2RuntimeActivationPolicy="true">
		<supportedRuntime version="v2.0"/>
		<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
	</startup>
</configuration>
 
 */
namespace PciDeviceLib
{
   public  class PCI_Control
    {
        object lock1 = new object();
        object lock2 = new object();
        object lock3 = new object();

        private UInt32 Rm_dwOffset;//存放转换寄存器地址
       // private UInt32 Wm_dwOffset;//存放转换寄存器地址
        private UInt32 R_u32Data;//读取
        //private UInt32 m_dwBytes;
       // private UInt32 W_u32Data;//写入

        public UInt32 WData;
        public UInt32 RData;
        private WDC_ADDR_MODE m_mode;
        private PCI_DeviceList pciDevList;
        public static List<String> pciDeviceList
        {
            get
            {
                return LIS;
            }
        }
        private static List<String> LIS ;
        /// <summary>
        /// 初始化设备方法参数为16进制写法，默认参数为0显示所有符合条件的ID，例如DeviceInit(0XC514,0);
        /// </summary>
        /// <param name="VENDOR_ID">厂商ID</param>
        /// <param name="DEVICE_ID">设备ID</param>
        /// <returns>所有符合条件的设备集合</returns>
        public  UInt32 DeviceInit(uint VENDOR_ID = 0, uint DEVICE_ID = 0)
        {
            LIS = new List<string>();
            pciDevList = PCI_DeviceList.TheDeviceList();

            pciDevList.PCI_DEFAULT_VENDOR_ID = VENDOR_ID;
            pciDevList.PCI_DEFAULT_DEVICE_ID = DEVICE_ID;


            UInt32 dwStatus = pciDevList.Init();
            if (dwStatus != 0)
                goto Error;

            Console.WriteLine("PCI设备初始化成功");
            foreach (PCI_Device dev in pciDevList)
            {
                LIS.Add(dev.ToString(false));
            }
            return dwStatus;
        Error:
            {
                Console.WriteLine("Error初始化错误");
                return dwStatus;
            }
        }
        /// <summary>
        /// 根据设备集合索引使能某个设备
        /// </summary>
        /// <param name="iSelectedIndex">所有符合条件的设备集合索引</param>
        /// <returns>为True时打开成功；为false时打开失败</returns>
        public UInt32 DeviceOpen(int iSelectedIndex)
        {
            PCI_Device device = pciDevList.Get(iSelectedIndex);
            return DeviceOpen( device);
        }
        /// <summary>
        /// 根据设备VID,DID使能某个设备
        /// </summary>
        /// <param name="VID">厂商编号</param>
        /// <param name="DID">设备编号</param>
        /// <returns>为True时打开成功；为false时打开失败</returns>
        public UInt32 DeviceOpen(UInt32 VID, UInt32 DID)
        {
            PCI_Device device = pciDevList.Get( VID,  DID);
            return DeviceOpen(device);
        }
        private UInt32 DeviceOpen(PCI_Device device)
        {
            UInt32 dwStatus;
         //   PCI_Device device = pciDevList.Get(iSelectedIndex);

            if (device == null)
            {
                Console.WriteLine("Error索引下设备不存在");
                return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
            }

            /* Open a handle to the device */
            dwStatus = device.Open();
            if ((UInt32)WD_ERROR_CODES.WD_STATUS_SUCCESS != dwStatus)
            {
                return dwStatus;
            }

            Console.WriteLine("已打开 " + device.ToString(false));

            return dwStatus;
        }
        /// <summary>
        /// 根据设备集合索引关闭某个设备
        /// </summary>
        /// <param name="iSelectedIndex">所有符合条件的设备集合索引</param>
        /// <returns>为True时成功；为false时失败</returns>
        public bool DeviceClose(int iSelectedIndex)
        {
            PCI_Device device = pciDevList.Get(iSelectedIndex);
            bool bStatus = false;
            if (device == null)
            {
                Console.WriteLine("Error索引下设备不存在");
                return false;
            }
            if (device.Handle != IntPtr.Zero && !(bStatus = device.Close()))
            {

                Console.WriteLine("关闭错误 " + device.ToString(false));

            }
            else
            {
                device.Handle = IntPtr.Zero;
                Console.WriteLine("关闭成功 " + device.ToString(false));
            }

            return bStatus;
        }
        /// <summary>
        /// 根据设备VID,DID关闭某个设备
        /// </summary>
        /// <param name="VID">厂商编号</param>
        /// <param name="DID">设备编号</param>
        /// <returns>为True时成功；为false时失败</returns>
        public bool DeviceClose(UInt32 VID, UInt32 DID)
        {
            PCI_Device device = pciDevList.Get(VID, DID);
            bool bStatus = false;
            if (device == null)
            {
                Console.WriteLine("Error索引下设备不存在");
                return false;
            }
            if (device.Handle != IntPtr.Zero && !(bStatus = device.Close()))
            {

                Console.WriteLine("关闭错误 " + device.ToString(false));

            }
            else
            {
                device.Handle = IntPtr.Zero;
                Console.WriteLine("关闭成功 " + device.ToString(false));
            }

            return bStatus;
        }
        public UInt32 ReadAddr32(int SlotID, UInt32 addr, ref UInt32 Rdata)
        {
            lock (lock1)
            {
                //  UINT32 ffset = (DWORD)Convert.ToInt32("2222", 16);
                //将寄存器地址装换格式
                //   Rm_dwOffset = (UInt32)Convert.ToInt32(addr, 16);
                Rm_dwOffset = addr;

                m_mode = WDC_ADDR_MODE.WDC_MODE_32;//设置32位读写

                //这个方法用枷锁吗
                PCI_Device dev = pciDevList.Get(SlotID);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                //数组显示Bar信息

                UInt32 m_dwBar = 2;

                UInt32 dWORD = wdc_lib_decl.WDC_ReadAddr32(dev.Handle, m_dwBar, Rm_dwOffset, ref R_u32Data);

                Rdata = R_u32Data;

                if ((UInt32)WD_ERROR_CODES.WD_STATUS_SUCCESS != dWORD)
                {
                    return dWORD;
                }
                string StrWm_dwOffset = Convert.ToString(Rm_dwOffset, 16);
                string TxtStrW = "R>>> Addr:" + StrWm_dwOffset + "H;RData:" + Convert.ToString(R_u32Data, 16) + "H；" + SlotID + "#.";
                Console.WriteLine(TxtStrW);
                return dWORD;
            }

        }
        public UInt32 ReadAddr32(UInt32 VID, UInt32 DID, UInt32 addr, ref UInt32 Rdata)
        {
            lock (lock1)
            {
                //  UINT32 ffset = (DWORD)Convert.ToInt32("2222", 16);
                //将寄存器地址装换格式
                //   Rm_dwOffset = (UInt32)Convert.ToInt32(addr, 16);
                Rm_dwOffset = addr;

                m_mode = WDC_ADDR_MODE.WDC_MODE_32;//设置32位读写

                //这个方法用枷锁吗
                PCI_Device dev = pciDevList.Get(VID,DID);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                //数组显示Bar信息

                UInt32 m_dwBar = 2;

                UInt32 dWORD = wdc_lib_decl.WDC_ReadAddr32(dev.Handle, m_dwBar, Rm_dwOffset, ref R_u32Data);

                Rdata = R_u32Data;
                if ((UInt32)WD_ERROR_CODES.WD_STATUS_SUCCESS != dWORD)
                {
                    return dWORD;
                }
                string StrWm_dwOffset = Convert.ToString(Rm_dwOffset, 16);
                string TxtStrW = "R>>> Addr:" + StrWm_dwOffset + "H;RData:" + Convert.ToString(R_u32Data, 16) + "H；VID:" + VID + "DID:" + DID;
                Console.WriteLine(TxtStrW);
                return dWORD;
            }

        }
        public UInt32 WriteAddr32(int SlotID, UInt32 Wm_dwOffset, UInt32 W_u32Data)
        {
            lock (lock2)
            {
                //  string SlotID = FormMain._GetDevice[index].SlotID.ToString();
                //  UINT32 ffset = (DWORD)Convert.ToInt32("2222", 16);
                //将寄存器地址装换格式
                //   Wm_dwOffset = (UInt32)Convert.ToInt32(addr, 16);

               //   W_u32Data = (UInt32)Convert.ToInt32(Wdata, 16);

                m_mode = WDC_ADDR_MODE.WDC_MODE_32;//设置32位读写

                if (pciDevList == null || pciDevList.Count == 0)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                PCI_Device dev = pciDevList.Get(SlotID);

                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                //数组显示Bar信息
                //string[] sBars = dev.AddrDescToString(false);

                UInt32 m_dwBar = 2;
                UInt32 dWORD = wdc_lib_decl.WDC_WriteAddr32(dev.Handle, m_dwBar, Wm_dwOffset, W_u32Data);
                string StrWm_dwOffset = Convert.ToString(Wm_dwOffset, 16);
                string TxtStrW = "W>>> Addr:" + StrWm_dwOffset + "H;WData:" + Convert.ToString(W_u32Data, 16) + "H；" + SlotID + "#.";
                Console.WriteLine(TxtStrW);

                return dWORD;
            }

        }
        public UInt32 WriteAddr32(UInt32 VID, UInt32 DID, UInt32 Wm_dwOffset, UInt32 W_u32Data)
        {
            lock (lock2)
            {
                //  string SlotID = FormMain._GetDevice[index].SlotID.ToString();
                //  UINT32 ffset = (DWORD)Convert.ToInt32("2222", 16);
                //将寄存器地址装换格式
                //   Wm_dwOffset = (UInt32)Convert.ToInt32(addr, 16);
                //   W_u32Data = (UInt32)Convert.ToInt32(Wdata, 16);

                m_mode = WDC_ADDR_MODE.WDC_MODE_32;//设置32位读写

                if (pciDevList == null || pciDevList.Count == 0)
                {

                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                PCI_Device dev = pciDevList.Get(VID, DID);

                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return (UInt32)WD_ERROR_CODES.WD_DEVICE_NOT_FOUND;//代表当前index下无设备
                }

                //数组显示Bar信息
                //     string[] sBars = dev.AddrDescToString(false);

                UInt32 m_dwBar = 2;

                UInt32 dWORD = wdc_lib_decl.WDC_WriteAddr32(dev.Handle, m_dwBar, Wm_dwOffset, W_u32Data);
                string StrWm_dwOffset = Convert.ToString(Wm_dwOffset, 16);
                string TxtStrW = "W>>> Addr:" + StrWm_dwOffset + "H;WData:" + Convert.ToString(W_u32Data, 16) + "H；VID:" + VID + "DID:" + DID ;
                Console.WriteLine(TxtStrW);

                return dWORD;
            }

        }

        #region DMA读取
        /// <summary>
        /// dma读取
        /// </summary>
        /// <param name="SlotID">索引号</param>
        /// <param name="addressHEX">首地址16进制格式</param>
        /// <param name="DMANumBytesHEX">偏移量16进制格式（偏移量由读取位数决定）</param>
        /// <param name="m_u32Data">读取缓存数组</param>
        /// <param name="AUTOINC">是否自动递增地址（默认True递增）</param>
        /// <param name="m_dwBar">读取的Bar区（默认读取 Bar 2）</param>
        /// <param name="MODE">读取格式（MODE=1为8位读取，MODE=2为16位读取，MODE=4为32位读取，MODE=8为64位读取；默认为32位读取）</param>
        /// <returns>操作成功返回True，失败则返回False</returns>
        public bool ReadAddrDMA(int SlotID, string addressHEX, string DMANumBytesHEX, ref UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            UInt32 m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
            UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
            PCI_Device dev = pciDevList.Get(SlotID);
            return ReadAddrDMA(dev, DMA_dwOffset, m_dwBytes, ref m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        public bool ReadAddrDMA(int SlotID, UInt32 addressHEX, UInt32 DMANumBytesHEX, ref UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            PCI_Device dev = pciDevList.Get(SlotID);
            return ReadAddrDMA(dev, addressHEX, DMANumBytesHEX, ref m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        public bool ReadAddrDMA(UInt32 VID, UInt32 DID, UInt32 addressHEX, UInt32 DMANumBytesHEX, ref UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            PCI_Device dev = pciDevList.Get(VID, DID);
            return ReadAddrDMA(dev, addressHEX, DMANumBytesHEX, ref m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        private bool ReadAddrDMA(PCI_Device dev, UInt32 addressHEX, UInt32 DMANumBytesHEX, ref UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            lock (lock3)
            {
                UInt32 dwStatus = 0;
                string ReadORWrite = "Read";
                bool DMA = true;//是否选择DMA
              //  bool AUTOINC = true;  //自动递增
             //   UInt32 m_dwBar = 2;
   
                    bool bIsBlock = (DMA) ? true : false;

                bool bIsRead = (ReadORWrite == "Read") ? true : false;

                //   PCI_Device dev = pciDevList.Get(SlotID);

                //  UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
                UInt32 DMA_dwOffset = addressHEX;
                switch (MODE)
                {
                    case 1: m_mode = WDC_ADDR_MODE.WDC_MODE_8; break;
                    case 2: m_mode = WDC_ADDR_MODE.WDC_MODE_16; break;
                    case 4: m_mode = WDC_ADDR_MODE.WDC_MODE_32; break;
                    case 8: m_mode = WDC_ADDR_MODE.WDC_MODE_64; break;
                }
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_8;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_16;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_32;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_64;


                WDC_ADDR_RW_OPTIONS dwOptions = (AUTOINC ?
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_DEFAULT :
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_NO_AUTOINC);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return false;
                }
                // m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
                UInt32 m_dwBytes = DMANumBytesHEX;
                if (m_dwBytes > dev.AddrDesc[m_dwBar].dwBytes)
                {
                    Console.WriteLine("Error Bar超范围");
                    return false;
                }
                  


                //    UINT32[] m_u32Data = new UINT32[m_dwBytes / 4];
                //   List<DWORD> RdataU32 = new List<DWORD>();

                UInt32 dwFloorBytes = ((UInt32)(m_dwBytes / (UInt32)m_mode)) * (UInt32)m_mode;


                dwStatus = wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle, m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data, m_mode, dwOptions);


                if (dwStatus == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

        }
        private bool ReadAddrDMA(PCI_Device dev, UInt32 addressHEX, UInt32 DMANumBytesHEX, ref object[] m_u333Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            lock (lock3)
            {
                UInt32 dwStatus = 0;
           
              
                                //  bool AUTOINC = true;  //自动递增
                                //   UInt32 m_dwBar = 2;

                bool bIsBlock = true;

                bool bIsRead = true ;
                // m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
                UInt32 m_dwBytes = DMANumBytesHEX;
                if (m_dwBytes > dev.AddrDesc[m_dwBar].dwBytes)
                {
                    Console.WriteLine("Error Bar超范围");
                    return false;
                }
                //   PCI_Device dev = pciDevList.Get(SlotID);

                //  UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
                UInt32 DMA_dwOffset = addressHEX;
                switch (MODE)
                {
                    case 1: m_mode = WDC_ADDR_MODE.WDC_MODE_8; break;
                    case 2: m_mode = WDC_ADDR_MODE.WDC_MODE_16; break;
                    case 4: m_mode = WDC_ADDR_MODE.WDC_MODE_32; break;
                    case 8: m_mode = WDC_ADDR_MODE.WDC_MODE_64; break;
                }
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_8;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_16;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_32;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_64;
                object[] m_obj;
                m_obj = new object[1];
                switch (m_mode)
                {
                    case WDC_ADDR_MODE.WDC_MODE_8:
                        {
                            m_bData = new byte[m_dwBytes];
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_16:
                        {
                            m_wData = new UInt16[m_dwBytes / 2];
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_32:
                        {
                            m_u32Data = new UInt32[m_dwBytes / 4];

                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_64:
                        {
                            m_u64Data = new UInt64[m_dwBytes / 8];


                            break;
                        }
                }

                WDC_ADDR_RW_OPTIONS dwOptions = (AUTOINC ?
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_DEFAULT :
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_NO_AUTOINC);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return false;
                }
  



                //    UINT32[] m_u32Data = new UINT32[m_dwBytes / 4];
                //   List<DWORD> RdataU32 = new List<DWORD>();

                UInt32 dwFloorBytes = ((UInt32)(m_dwBytes / (UInt32)m_mode)) * (UInt32)m_mode;


                //     dwStatus = wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle, m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data, m_mode, dwOptions);
                switch (m_mode)
                {
                    case WDC_ADDR_MODE.WDC_MODE_8:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_bData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr8(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_bData[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_bData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr8(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_bData[0]);

                            m_obj[0] = m_bData;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_16:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_wData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr16(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_wData[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_wData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr16(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_wData[0]);

                            m_obj[0] = m_wData;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_32:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr32(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_u32Data[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr32(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_u32Data[0]);

                            m_obj[0] = m_u32Data;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_64:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u64Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr64(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_u64Data[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u64Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr64(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_u64Data[0]);

                            m_obj[0] = m_u64Data;
                            break;
                        }
                }
                m_u333Data = m_obj;

                if (dwStatus == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

        }
        #endregion

        #region DMA写
        // public static uint WDC_WriteAddrBlock(IntPtr hDev, uint dwAddrSpace, ulong dwOffset, uint dwBytes, uint[] pData, WDC_ADDR_MODE mode, WDC_ADDR_RW_OPTIONS options);
        /// <summary>
        /// dma写操作
        /// </summary>
        /// <param name="SlotID">索引号</param>
        /// <param name="addressHEX">首地址16进制格式</param>
        /// <param name="DMANumBytesHEX">偏移量16进制格式（偏移量由读取位数决定）</param>
        /// <param name="m_u32Data">待写入缓存数组</param>
        /// <param name="AUTOINC">是否自动递增地址（默认True递增）</param>
        /// <param name="m_dwBar">读取的Bar区（默认读取 Bar 2）</param>
        /// <param name="MODE">读取格式（MODE=1为8位读取，MODE=2为16位读取，MODE=4为32位读取，MODE=8为64位读取；默认为32位读取）</param>
        /// <returns>操作成功返回True，失败则返回False</returns>
        public bool WriteAddrDMA(int SlotID, string addressHEX, string DMANumBytesHEX, UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            UInt32 m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
            UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
            PCI_Device dev = pciDevList.Get(SlotID);
            return WriteAddrDMA(dev, DMA_dwOffset, m_dwBytes, m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        public bool WriteAddrDMA(int SlotID, UInt32 addressHEX, UInt32 DMANumBytesHEX, UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            PCI_Device dev = pciDevList.Get(SlotID);
            return WriteAddrDMA(dev, addressHEX, DMANumBytesHEX, m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        public bool WriteAddrDMA(UInt32 VID, UInt32 DID, UInt32 addressHEX, UInt32 DMANumBytesHEX, UInt32[] m_u32Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            PCI_Device dev = pciDevList.Get(VID, DID);
            return WriteAddrDMA(dev, addressHEX, DMANumBytesHEX, m_u32Data, AUTOINC, m_dwBar, MODE);
        }
        private bool WriteAddrDMA(PCI_Device dev, UInt32 addressHEX, UInt32 DMANumBytesHEX, UInt32[] m_u333Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            lock (lock3)
            {
                UInt32 dwStatus = 0;
                string ReadORWrite = "Read";
                bool DMA = true;//是否选择DMA
                                // bool AUTOINC = true;  //自动递增
                                //  UInt32 m_dwBar = 2;
               // byte[] m_bDataByte;
                bool bIsBlock = (DMA) ? true : false;

                bool bIsRead = (ReadORWrite == "Read") ? true : false;
                // m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
                UInt32 m_dwBytes = DMANumBytesHEX;
                if (m_dwBytes > dev.AddrDesc[m_dwBar].dwBytes)
                {
                    Console.WriteLine("Error Bar超范围");
                    return false;
                }
                //   PCI_Device dev = pciDevList.Get(SlotID);

                //  UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
                UInt32 DMA_dwOffset = addressHEX;
                switch (MODE)
                {
                    case 1: m_mode = WDC_ADDR_MODE.WDC_MODE_8; break;
                    case 2: m_mode = WDC_ADDR_MODE.WDC_MODE_16; break;
                    case 4: m_mode = WDC_ADDR_MODE.WDC_MODE_32; break;
                    case 8: m_mode = WDC_ADDR_MODE.WDC_MODE_64; break;
                }
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_8;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_16;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_32;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_64;

                WDC_ADDR_RW_OPTIONS dwOptions = (AUTOINC ?
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_DEFAULT :
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_NO_AUTOINC);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return false;
                }



                //    UINT32[] m_u32Data = new UINT32[m_dwBytes / 4];
                //   List<DWORD> RdataU32 = new List<DWORD>();

                UInt32 dwFloorBytes = ((UInt32)(m_dwBytes / (UInt32)m_mode)) * (UInt32)m_mode;

                // public static uint WDC_WriteAddrBlock(IntPtr hDev, uint dwAddrSpace, ulong dwOffset, uint dwBytes, uint[] pData, WDC_ADDR_MODE mode, WDC_ADDR_RW_OPTIONS options);
                dwStatus = wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle, m_dwBar, DMA_dwOffset, dwFloorBytes, m_u333Data, m_mode, dwOptions);


                if (dwStatus == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

        }

        private byte[] m_bData;
        private UInt16[] m_wData;
        private UInt32[] m_u32Data;
        private UInt64[] m_u64Data;
        private bool WriteAddrDMA(PCI_Device dev, UInt32 addressHEX, UInt32 DMANumBytesHEX, object[] m_u333Data, bool AUTOINC = true, UInt32 m_dwBar = 2, UInt32 MODE = 4)
        {
            lock (lock3)
            {
                UInt32 dwStatus = 0;


                // bool AUTOINC = true;  //自动递增
                //  UInt32 m_dwBar = 2;

                bool bIsBlock = true;

                bool bIsRead = false;
                // m_dwBytes = Convert.ToUInt32(DMANumBytesHEX, 16);
                UInt32 m_dwBytes = DMANumBytesHEX;
                if (m_dwBytes > dev.AddrDesc[m_dwBar].dwBytes)
                {
                    Console.WriteLine("Error Bar超范围");
                    return false;
                }
                //   PCI_Device dev = pciDevList.Get(SlotID);

                //  UInt32 DMA_dwOffset = (UInt32)Convert.ToInt32(addressHEX, 16);
                UInt32 DMA_dwOffset = addressHEX;
                switch (MODE)
                {
                    case 1: m_mode = WDC_ADDR_MODE.WDC_MODE_8; break;
                    case 2: m_mode = WDC_ADDR_MODE.WDC_MODE_16; break;
                    case 4: m_mode = WDC_ADDR_MODE.WDC_MODE_32; break;
                    case 8: m_mode = WDC_ADDR_MODE.WDC_MODE_64; break;
                }
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_8;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_16;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_32;
                //   m_mode = WDC_ADDR_MODE.WDC_MODE_64;
                object[] m_obj;
                m_obj = new object[1];
                switch (m_mode)
                {
                    case WDC_ADDR_MODE.WDC_MODE_8:
                        {
                            m_bData = new byte[m_dwBytes];
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_16:
                        {
                            m_wData = new UInt16[m_dwBytes / 2];
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_32:
                        {
                            m_u32Data = new UInt32[m_dwBytes / 4];

                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_64:
                        {
                            m_u64Data = new UInt64[m_dwBytes / 8];


                            break;
                        }
                }
                WDC_ADDR_RW_OPTIONS dwOptions = (AUTOINC ?
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_DEFAULT :
                    WDC_ADDR_RW_OPTIONS.WDC_ADDR_RW_NO_AUTOINC);
                if (dev == null)
                {
                    Console.WriteLine("Error索引下设备不存在");
                    return false;
                }



                //    UINT32[] m_u32Data = new UINT32[m_dwBytes / 4];
                //   List<DWORD> RdataU32 = new List<DWORD>();

                UInt32 dwFloorBytes = ((UInt32)(m_dwBytes / (UInt32)m_mode)) * (UInt32)m_mode;

                // public static uint WDC_WriteAddrBlock(IntPtr hDev, uint dwAddrSpace, ulong dwOffset, uint dwBytes, uint[] pData, WDC_ADDR_MODE mode, WDC_ADDR_RW_OPTIONS options);
                switch (m_mode)
                {
                    case WDC_ADDR_MODE.WDC_MODE_8:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_bData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr8(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_bData[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_bData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr8(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_bData[0]);

                            m_obj[0] = m_bData;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_16:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_wData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr16(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_wData[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_wData,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr16(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_wData[0]);

                            m_obj[0] = m_wData;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_32:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr32(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_u32Data[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u32Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr32(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_u32Data[0]);

                            m_obj[0] = m_u32Data;
                            break;
                        }
                    case WDC_ADDR_MODE.WDC_MODE_64:
                        {
                            if (bIsRead)
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_ReadAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u64Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_ReadAddr64(dev.Handle,
                                        m_dwBar, DMA_dwOffset, ref m_u64Data[0]);
                            else
                                dwStatus = bIsBlock ?
                                    wdc_lib_decl.WDC_WriteAddrBlock(dev.Handle,
                                        m_dwBar, DMA_dwOffset, dwFloorBytes, m_u64Data,
                                        m_mode, dwOptions) :
                                    wdc_lib_decl.WDC_WriteAddr64(dev.Handle,
                                        m_dwBar, DMA_dwOffset, m_u64Data[0]);

                            m_obj[0] = m_u64Data;
                            break;
                        }
                }
                m_u333Data = m_obj;

                if (dwStatus == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

        }

        #endregion
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            pciDevList.Dispose();
        }
        public string DisplayHexBuffer(object[] obj,int mode)
        {

        //WDC_MODE_8 = 1,
        //WDC_MODE_16 = 2,
        //WDC_MODE_32 = 4,
        //WDC_MODE_64 = 8
            
            string display = "";


            UInt32 dwBuffSize = (UInt32)((m_mode == WDC_ADDR_MODE.WDC_MODE_8) ? 1 :
                  ((m_mode == WDC_ADDR_MODE.WDC_MODE_16) ? 2 :
                  ((m_mode == WDC_ADDR_MODE.WDC_MODE_32) ? 4 : 8)));

            switch ((WDC_ADDR_MODE)mode)
            {
                case WDC_ADDR_MODE.WDC_MODE_8:
                    {
                        byte[] buff = (byte[])obj[0];
                        for (uint i = 0; i < dwBuffSize; ++i)
                            display = string.Concat(display,
                                buff[i].ToString("X2"), " ");
                        break;
                    }
                case WDC_ADDR_MODE.WDC_MODE_16:
                    {
                        UInt16[] buff = (UInt16[])obj[0];
                        for (int i = 0; i < dwBuffSize / 2; ++i)
                            display = string.Concat(display,
                                buff[i].ToString("X4"), " ");
                        break;
                    }
                case WDC_ADDR_MODE.WDC_MODE_32:
                    {
                        UInt32[] buff = (UInt32[])obj[0];
                        for (int i = 0; i < dwBuffSize / 4; ++i)
                            display = string.Concat(display,
                                buff[i].ToString("X8"), " ");
                        break;
                    }
                case WDC_ADDR_MODE.WDC_MODE_64:
                    {
                        UInt64[] buff = (UInt64[])obj[0];
                        for (int i = 0; i < dwBuffSize / 8; ++i)
                            display = string.Concat(display,
                                buff[i].ToString("X16"), " ");
                        break;
                    }
            }
            return display;
        }
    }
}
